using System;

namespace OpenCvSharp
{
    public enum CvTransition
    {
        All = 0,
        Positive = 1,
        Negative = 2
    }

    public enum CvSelect
    {
        [Obsolete("Spare", true)]//不会写的卡尺测量模式，不知道怎么分开结果
        All = 0,
        First = 1,
        Last = 2,
        Max = 3
    }

    public enum CvDirection
    {
        Forward=0,
        Reverse=1
    }

    public struct CvPoint : IEquatable<CvPoint>
    {
        public double X { get; set; }

        public double Y { get; set; }

        public CvPoint(double x, double y)
        {
            X = x;
            Y = y;
        }

        public static implicit operator CvPoint(System.Drawing.Point p)
        {
            return new CvPoint(p.X, p.Y);
        }
        public static implicit operator System.Drawing.Point(CvPoint p)
        {
            return new System.Drawing.Point((int)p.X, (int)p.Y);
        }

        public static implicit operator CvPoint(System.Drawing.PointF p)
        {
            return new CvPoint(p.X, p.Y);
        }
        public static implicit operator System.Drawing.PointF(CvPoint p)
        {
            return new System.Drawing.PointF((float)p.X, (float)p.Y);
        }

        public static implicit operator CvPoint(Point p)
        {
            return new CvPoint(p.X, p.Y);
        }
        public static implicit operator Point(CvPoint p)
        {
            return new Point(p.X, p.Y);
        }

        public static implicit operator CvPoint(Point2d p)
        {
            return new CvPoint(p.X, p.Y);
        }
        public static implicit operator Point2d(CvPoint p)
        {
            return new Point2d(p.X, p.Y);
        }

        public static implicit operator CvPoint(Point2f p)
        {
            return new CvPoint(p.X, p.Y);
        }
        public static implicit operator Point2f(CvPoint p)
        {
            return new Point2f((float)p.X, (float)p.Y);
        }

        public static implicit operator CvPoint(Vec2d p)
        {
            return new CvPoint(p.Item0, p.Item1);
        }
        public static implicit operator Vec2d(CvPoint p)
        {
            return new Vec2d(p.X, p.Y);
        }

        public static bool operator ==(CvPoint p1, CvPoint p2)
        {
            return p1.X == p2.X && p1.Y == p2.Y;
        }
        public static bool operator !=(CvPoint p1, CvPoint p2)
        {
            return !(p1 == p2);
        }

        public override bool Equals(object obj)
        {
            if (obj is CvPoint)
            {
                return Equals((CvPoint)obj);
            }
            return false;
        }

        public bool Equals(CvPoint other)
        {
            return other == this;
        }

        public override int GetHashCode()
        {
            return X.GetHashCode() ^ Y.GetHashCode();
        }

        public override string ToString()
        {
            return string.Join(", ", X, Y);
        }
    }

    public struct CvSize : IEquatable<CvSize>
    {
        public double Width { get; set; }

        public double Height { get; set; }

        public CvSize(double width, double height)
        {
            Width = width;
            Height = height;
        }

        public static implicit operator CvSize(System.Drawing.Size s)
        {
            return new CvSize(s.Width, s.Height);
        }
        public static implicit operator System.Drawing.Size(CvSize s)
        {
            return new System.Drawing.Size((int)s.Width, (int)s.Height);
        }

        public static implicit operator CvSize(System.Drawing.SizeF s)
        {
            return new CvSize(s.Width, s.Height);
        }
        public static implicit operator System.Drawing.SizeF(CvSize s)
        {
            return new System.Drawing.SizeF((float)s.Width, (float)s.Height);
        }

        public static implicit operator CvSize(Size s)
        {
            return new CvSize(s.Width, s.Height);
        }
        public static implicit operator Size(CvSize s)
        {
            return new Size(s.Width, s.Height);
        }

        public static implicit operator CvSize(Size2d s)
        {
            return new CvSize(s.Width, s.Height);
        }
        public static implicit operator Size2d(CvSize s)
        {
            return new Size2d(s.Width, s.Height);
        }

        public static implicit operator CvSize(Size2f s)
        {
            return new CvSize(s.Width, s.Height);
        }
        public static implicit operator Size2f(CvSize s)
        {
            return new Size2f((float)s.Width, (float)s.Height);
        }

        public static implicit operator CvSize(Vec2d s)
        {
            return new CvSize(s.Item0, s.Item1);
        }
        public static implicit operator Vec2d(CvSize s)
        {
            return new Vec2d(s.Width, s.Height);
        }

        public static bool operator ==(CvSize s1, CvSize s2)
        {
            return s1.Width == s2.Width && s1.Height == s2.Height;
        }
        public static bool operator !=(CvSize s1, CvSize s2)
        {
            return !(s1 == s2);
        }

        public override bool Equals(object obj)
        {
            if (obj is CvSize)
            {
                return Equals((CvSize)obj);
            }
            return false;
        }

        public bool Equals(CvSize other)
        {
            return other == this;
        }

        public override int GetHashCode()
        {
            return Width.GetHashCode() ^ Height.GetHashCode();
        }

        public override string ToString()
        {
            return string.Join(", ", Width, Height);
        }
    }

    public struct CvLine : IEquatable<CvLine>
    {
        public double BeginX { get; set; }

        public double BeginY { get; set; }

        public double EndX { get; set; }

        public double EndY { get; set; }

        public CvPoint BeginPoint
        {
            get
            {
                return new CvPoint(BeginX, BeginY);
            }
            set
            {
                BeginX = value.X;
                BeginY = value.Y;
            }
        }

        public CvPoint EndPoint
        {
            get
            {
                return new CvPoint(EndX, EndY);
            }
            set
            {
                EndX = value.X;
                EndY = value.Y;
            }
        }

        public CvLine(CvPoint beginPoint, CvPoint endPoint)
            : this(beginPoint.X, beginPoint.Y, endPoint.X, endPoint.Y) { }

        public CvLine(double beginX, double beginY, double endX, double endY)
        {
            BeginX = beginX;
            BeginY = beginY;
            EndX = endX;
            EndY = endY;
        }

        public static implicit operator CvLine(LineSegmentPoint l)
        {
            return new CvLine(l.P1, l.P2);
        }
        public static implicit operator LineSegmentPoint(CvLine l)
        {
            return new LineSegmentPoint(l.BeginPoint, l.EndPoint);
        }

        public static implicit operator CvLine(Vec4d l)
        {
            return new CvLine(l.Item0, l.Item1, l.Item2, l.Item3);
        }
        public static implicit operator Vec4d(CvLine l)
        {
            return new Vec4d(l.BeginX, l.BeginY, l.EndX, l.EndY);
        }

        public static bool operator ==(CvLine l1, CvLine l2)
        {
            return l1.BeginPoint == l2.BeginPoint && l1.EndPoint == l2.EndPoint;
        }
        public static bool operator !=(CvLine l1, CvLine l2)
        {
            return !(l1 == l2);
        }

        public override bool Equals(object obj)
        {
            if (obj is CvLine)
            {
                return Equals((CvLine)obj);
            }
            return false;
        }

        public bool Equals(CvLine other)
        {
            return other == this;
        }

        public override int GetHashCode()
        {
            return BeginPoint.GetHashCode() ^ EndPoint.GetHashCode();
        }

        public override string ToString()
        {
            return string.Join(", ", BeginPoint, EndPoint);
        }
    }

    public struct CvCircle : IEquatable<CvCircle>
    {
        public double CenterX { get; set; }

        public double CenterY { get; set; }

        public double Radius { get; set; }

        public CvPoint Center
        {
            get
            {
                return new CvPoint(CenterX, CenterY);
            }
            set
            {
                CenterX = value.X;
                CenterY = value.Y;
            }
        }

        public CvCircle(CvPoint center, double radius)
            : this(center.X, center.Y, radius) { }

        public CvCircle(double centerX, double centerY, double radius)
        {
            CenterX = centerX;
            CenterY = centerY;
            Radius = radius;
        }

        public static implicit operator CvCircle(Vec3d c)
        {
            return new CvCircle(c.Item0, c.Item1, c.Item2);
        }
        public static implicit operator Vec3d(CvCircle c)
        {
            return new Vec3d(c.CenterX, c.CenterY, c.Radius);
        }

        public static implicit operator CvCircle(CircleSegment c)
        {
            return new CvCircle(c.Center, c.Radius);
        }
        public static implicit operator CircleSegment(CvCircle c)
        {
            return new CircleSegment(c.Center, (float)c.Radius);
        }

        public static bool operator ==(CvCircle c1, CvCircle c2)
        {
            return c1.Center == c2.Center && c1.Radius == c2.Radius;
        }
        public static bool operator !=(CvCircle c1, CvCircle c2)
        {
            return !(c1 == c2);
        }

        public override bool Equals(object obj)
        {
            if (obj is CvCircle)
            {
                return Equals((CvCircle)obj);
            }
            return false;
        }

        public bool Equals(CvCircle other)
        {
            return other == this;
        }

        public override int GetHashCode()
        {
            return Center.GetHashCode() ^ Radius.GetHashCode();
        }

        public override string ToString()
        {
            return string.Join(", ", Center, Radius);
        }
    }

    public struct CvRect : IEquatable<CvRect>
    {
        public double X { get; set; }

        public double Y { get; set; }

        public double Width { get; set; }

        public double Height { get; set; }

        public CvPoint Location
        {
            get
            {
                return new CvPoint(X, Y);
            }
            set
            {
                X = value.X;
                Y = value.Y;
            }
        }

        public CvSize Size
        {
            get
            {
                return new CvSize(Width, Height);
            }
            set
            {
                Width = value.Width;
                Height = value.Height;
            }
        }

        public CvRect(CvPoint location, CvSize size)
            : this(location.X, location.Y, size.Width, size.Height) { }

        public CvRect(double x, double y, double width, double height)
        {
            X = x;
            Y = y;
            Width = width;
            Height = height;
        }

        public static implicit operator CvRect(System.Drawing.Rectangle r)
        {
            return new CvRect(r.X, r.Y, r.Width, r.Height);
        }
        public static implicit operator System.Drawing.Rectangle(CvRect r)
        {
            return new System.Drawing.Rectangle((int)r.X, (int)r.Y, (int)r.Width, (int)r.Height);
        }

        public static implicit operator CvRect(System.Drawing.RectangleF r)
        {
            return new CvRect(r.X, r.Y, r.Width, r.Height);
        }
        public static implicit operator System.Drawing.RectangleF(CvRect r)
        {
            return new System.Drawing.RectangleF((float)r.X, (float)r.Y, (float)r.Width, (float)r.Height);
        }

        public static implicit operator CvRect(Rect r)
        {
            return new CvRect(r.X, r.Y, r.Width, r.Height);
        }
        public static implicit operator Rect(CvRect r)
        {
            return new Rect((int)r.X, (int)r.Y, (int)r.Width, (int)r.Height);
        }

        public static implicit operator CvRect(Rect2d r)
        {
            return new CvRect(r.X, r.Y, r.Width, r.Height);
        }
        public static implicit operator Rect2d(CvRect r)
        {
            return new Rect2d(r.X, r.Y, r.Width, r.Height);
        }

        public static implicit operator CvRect(Rect2f r)
        {
            return new CvRect(r.X, r.Y, r.Width, r.Height);
        }
        public static implicit operator Rect2f(CvRect r)
        {
            return new Rect2f((float)r.X, (float)r.Y, (float)r.Width, (float)r.Height);
        }

        public static implicit operator CvRect(Vec4d r)
        {
            return new CvRect(r.Item0, r.Item1, r.Item2, r.Item3);
        }
        public static implicit operator Vec4d(CvRect r)
        {
            return new Vec4d(r.X, r.Y, r.Width, r.Height);
        }

        public static bool operator ==(CvRect r1, CvRect r2)
        {
            return r1.Location == r2.Location && r1.Size == r2.Size;
        }
        public static bool operator !=(CvRect r1, CvRect r2)
        {
            return !(r1 == r2);
        }

        public override bool Equals(object obj)
        {
            if (obj is CvRect)
            {
                return Equals((CvRect)obj);
            }
            return false;
        }

        public bool Equals(CvRect other)
        {
            return other == this;
        }

        public override int GetHashCode()
        {
            return Location.GetHashCode() ^ Size.GetHashCode();
        }

        public override string ToString()
        {
            return string.Join(",", Location, Size);
        }
    }

    public struct CvRotatedRect : IEquatable<CvRotatedRect>
    {
        public double CenterX { get; set; }

        public double CenterY { get; set; }

        public double Angle { get; set; }

        public double Width { get; set; }

        public double Height { get; set; }

        public CvPoint Center
        {
            get
            {
                return new CvPoint(CenterX, CenterY);
            }
            set
            {
                CenterX = value.X;
                CenterY = value.Y;
            }
        }

        public CvSize Size
        {
            get
            {
                return new CvSize(Width, Height);
            }
            set
            {
                Width = value.Width;
                Height = value.Height;
            }
        }

        public CvRotatedRect(CvPoint center, double angle, CvSize size)
            : this(center.X, center.Y, angle, size.Width, size.Height) { }

        public CvRotatedRect(double centerX, double centerY, double angle, double width, double height)
        {
            CenterX = centerX;
            CenterY = centerY;
            Angle = angle;
            Width = width;
            Height = height;
        }

        public static implicit operator CvRotatedRect(RotatedRect r)
        {
            return new CvRotatedRect(r.Center.X, r.Center.Y, r.Angle, r.Size.Width, r.Size.Height);
        }
        public static implicit operator RotatedRect(CvRotatedRect r)
        {
            return new RotatedRect(r.Center, r.Size, (float)r.Angle);
        }

        public static bool operator ==(CvRotatedRect r1, CvRotatedRect r2)
        {
            return r1.Center == r2.Center && r1.Angle == r2.Angle && r1.Size == r2.Size;
        }
        public static bool operator !=(CvRotatedRect r1, CvRotatedRect r2)
        {
            return !(r1 == r2);
        }

        public override bool Equals(object obj)
        {
            if (obj is CvRotatedRect)
            {
                return Equals((CvRotatedRect)obj);
            }
            return false;
        }

        public bool Equals(CvRotatedRect other)
        {
            return other == this;
        }

        public override int GetHashCode()
        {
            return Center.GetHashCode() ^ Angle.GetHashCode() ^ Size.GetHashCode();
        }

        public override string ToString()
        {
            return string.Join(",", Center, Angle, Size);
        }
    }
}
